// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

#ifndef _SAMPLE_H_
#define _SAMPLE_H_

/*! 
\defgroup	gio Genomic I/O Library
\brief		Genomic I/O Utility Library
\details	Routines concerned with the loading of genomic data into parallelised
			statistical programs.<br>
			Initially based on the text based file formats used by PLINK.<br>
			Later converted to simpler binary format to optimise
			data uploads to the cores of the NIBHI cluster.
*/

/*!
\file
\ingroup	gio
\brief		Sample/Phenotype Methods
\details	Header File encapsulating an individual/person in a genomic data-set.
*/
#include "pedfile.h"
#include "options.h"
#include "types.h"

#ifdef __cplusplus
extern "C" {
#endif

/*! \brief Default Strata or Layer */
#define DEFAULT_SOL -1

/*!
\brief		Sample/Person Structure (Binary Format)
\details	
<p>Structure representing an individual in data set of genomic information.
This data-type contains the phenotype information of a response variable,
the gender of the person and any associated strata/level membership of a related environmental
factor.</p>

<p>This structure is the run-time representation of a  person 
used by the processing cores of the NIBHI cluster. 
This structure is a slimmed down version of \ref individual
which in turn is derived from a equivalent data-definition within PLINK.
Superfluous data members have been removed so that the data-type 
contains only fields that are used in the analysis algorithms.
Unlike PLINK, no identifier fields are included with this structure.
This structure is associated with other data entities by array index.</p>

<p>Binary arrays of sample data are created by reading genomic data 
from either a PLINK-compatible text file or from binary encoded input file.
Sample arrays can be created by reading a pedigree file (\ref pedfile) 
containing the genomic information of a data-set and a phenotype file (\ref individual \ref phefile.h)
containing the response variable of individuals being analysed. 
Following the application
logic of PLINK, this information is loaded into the \ref pedfile structure, 
with the phenotype data bound to the sample array. The genomic information is bound to the \ref individual::one
and \ref individual::two arrays of \ref individual.
The sample array of PLINK is written to separate binary file (\ref SUFFIX_SAMPLE_FILE) 
and this file is what is distributed to the NIBHI processing nodes. 
</p>
\see individual */
struct sample {
	/*! \brief Flag if phenotype missing or strata membership missing */  
	BOOL missing; 
	/*! \brief Gender of the individual (TRUE = male) */
	BOOL sex;	  
	/*! \brief Flag for BT phenotype (if affected = TRUE) */
	BOOL aff;     
	/*! \brief Value for a continuous/ordinal/qualitative phenotype */
	double phenotype; 
	/*! 
	\brief Pointer to another index in a sample array. 
	\details
		Resetting this pointer is how phenotypes of a data-set are re-ordered for permutation calculations.
		By default, this value is set initially to a NULL pointer.
		When a statistical code is performing a calculation, phenotype data is obtained by referencing this pointer to
		access the \ref sample::aff or \ref sample::phenotype fields.
		Before a statistical calculation is done, the function \ref samplefile_set_original_order() should be 
		called to set the original order for the data-set phenotype and so avoid a NULL pointer exception.
		Statistical codes do not check the NULL-status of this field to save cycles.
	\see samplefile_set_original_order()
	\see permute()
	\see samplefile_permute_phenotype()
	*/
	struct sample *pperson; 
	/*! 
	\brief Strata or Layer, CMH analysis column. 
	\details 
		Typical value 0 to N-1 where N = number of unique values in a level.
		If a individual is not assigned to a level, \ref sample::sol set to -1.
	*/
	int sol; 
};

/*! 
\brief Create a sample file
\details
	The map (\ref mapfile), pedigree (\ref pedfile) and phenotype data 
	must be read and bound to a \ref pedfile before the <em>sample</em> data can be written to a binary file.
	By default sample files use the suffix \ref SUFFIX_SAMPLE_FILE .
	The sample file starts with an integer recording the number of sample structures contained 
	within the sample file.
\param[in] ops 
	Structure containing the file path to the sample file.
	Filepath bound to \ref selected_options::szSampleFileName .
\param[in] ped 
		Pedfile structure containing the genomic/phenotype data read 
		from a PLINK-compatible text file input.
\return TRUE if file created successfully.
\see mapfile_read()
\see pedfile_read()
*/
int samplefile_create(struct selected_options *ops, struct pedfile *ped);

/*!
\brief Load a sample file
\param[in] ops 
	Structure containing the file path to the sample file.
	Filepath bound to \ref selected_options::szSampleFileName .
\param[in,out] nSamples Pointer that stores the number of samples in the file (set to zero on failure).
\return a \ref sample array of size nSamples (or NULL on failure). */
struct sample* samplefile_load(struct selected_options *ops, int *nSamples);

/*!
\brief %Set the phenotypes of a data-set to the original order, i.e. non-permuted.
\details
	Simply means that the owner of a sample::pperson references itself instead of being set to NULL.
\param[in, out] samples the \ref sample array
\param[in] nSamples Size of the sample array.
\return 1 on success, 0 on failure. */
int samplefile_set_original_order(struct sample *samples, int nSamples);

/*!
\brief Assign the affected status phenotype for a binary trait (aff/unaff).
\details 
	Depends on what value assigned to phenotype field and whether the individual classed as missing.
	If phenotype assigned coded value of '2', record judged to be of affected status.
\param[in, out] samples the \ref sample array
\param[in] nSamples Size of the sample array.
\return 1 on success, 0 on failure. */
int samplefile_aff_coding(struct sample *samples, int nSamples);

/*!
\brief Permute the sample phenotype
\details 
	Permute the sample phenotype by re-assigned the references of \ref sample::pperson to a new values
	specified by the 'perms' integer array. The 'perms' array may be populated by a call to
	\ref permute() .
\param[in, out] samples the \ref sample array
\param[in] perms 
	Pointer to the permutation array.
	Each element value must be unique and equal to 0 to nSamples-1 
\param[in] nSamples Size of the sample array
\return 1 on success, 0 on failure.*/
int samplefile_permute_phenotype(struct sample *samples, int *perms, int nSamples);

/*! \brief Copy the missing flag of the structure to a BOOL array. 
\details 
	The method has a functional redundancy with sample::missing but has been kept to maintain
	codebase similarity with PLINK.
\param[in, out] missing Destination array for the contents of the sample::missing field.
\param[in, out] nMissing Size of the input arrays.
\param[in] s the \ref sample array
\return 1 on success, 0 on failure. */
int samplefile_set_missing(BOOL *missing, int nMissing, struct sample *s);

/*! \brief Assign sample to default strata if flagged as missing.
\param[in] s the \ref sample array
\param[in, out] nSamples Size of the input array.
\return 1 on success, 0 on failure.
\see DEFAULT_SOL */
int samplefile_set_missing_by_sol(struct sample *s, int nSamples);

/*!
\brief Create a Samples file and copy to a remore directory.
\details
	Create a sample file from a populated genomic data-set (see \ref pedfile)
	and copies the output file to a remote directory.<br>
	The output file path is a concatonation of \ref selected_options::rdir, 
	\ref selected_options::szRunId and \ref SUFFIX_SAMPLE_FILE .
\param[in] ops Output file location
\param[in] p Genomic data-set containing the phenotype data
\param[in] rank Rank of the local processor
\returns 1 on success or 0 on failure
*/
int samplefile_create_and_copy(struct selected_options *ops, struct pedfile *p, int rank);

/*! 
\brief Load a Sample file
\details
	The input file path is a concatonation of \ref selected_options::rdir, 
	\ref selected_options::szRunId and \ref SUFFIX_SAMPLE_FILE .
\param [in] ops Input file location
\param [in, out] nSamples size of the loaded array
\return an array of \ref sample or NULL on failure
*/
struct sample* _samplefile_load(struct selected_options *ops, int *nSamples);

/*!
\brief Create a %Sample File and Copy to Central File System
\param [in] ops output file location
\param [in] phenotypes The phenotypes array
\param [in]	phe_is_missing Flag is phenotype is missing
\param [in] nPhenotypes Size of the phenotype array
\param [in] sex Gender Array
\returns 1 on sucess, 0 on failure
*/
int _samplefile_create_and_copy(struct selected_options *ops, double *phenotypes, BOOL *phe_is_missing, int nPhenotypes, BOOL *sex);

/*!
\brief Echo a Sample Structure to STDOUT 
\param s A %sample Structure
*/
void sample_echo(struct sample *s);

#ifdef __cplusplus
}
#endif

#endif // _SAMPLE_H_
